﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace Mines
{
    public partial class MainForm : Form
    {
        Cell[,] Field;
        int nGameFieldSize = 20;
        int nNumOfMines = 100;
        int nNumOfCellsToOpen;
        bool bGameFieldInited = false;

        struct Cell
        {
            public int x, y;
            public int nValue;
            public bool bOpened;
            public bool bFlag;
            public void Draw(Control control)
            {
                Graphics g = control.CreateGraphics();
                SolidBrush brush = new SolidBrush(Color.Blue);
                System.Drawing.Font font = new Font("Segoe UI", 14);
                Pen pen = new Pen(Color.Purple);
                if (!bFlag && !bOpened)
                {
                    
                    brush.Color = Color.SkyBlue;
                    g.FillRectangle(brush, x * 30, y * 30, 30, 30);
                    g.DrawRectangle(pen, x * 30, y * 30, 30, 30);
                }
                else if (!bFlag && bOpened)
                {
                    switch (this.nValue)
                    {
                        case -1:
                            brush.Color = Color.Red;
                            g.FillEllipse(brush, x * 30 + 7, y * 30 + 7, 15, 15);
                            break;
                        case 0:
                            brush.Color = Color.Green;
                            g.FillRectangle(brush, x * 30, y * 30, 30, 30);
                            break;
                        default:
                            g.DrawString(this.nValue.ToString(), font, brush, x * 30 + 6, y * 30 + 2);
                            break;
                    }
                }
                else if(bFlag)
                {
                    brush.Color = Color.Red;
                    g.FillEllipse(brush, x * 30 + 7, y * 30 + 7, 15, 15);
                    brush.Color = Color.Snow;
                    g.FillEllipse(brush, x * 30 + 11, y * 30 + 11, 7, 7);
                }
                pen.Dispose();
                font.Dispose();
                brush.Dispose();
                g.Dispose();
            }
        }

        public MainForm()
        {
            InitializeComponent();
        }

        private void InitGameField(int x, int y)
        {
            nNumOfCellsToOpen = nGameFieldSize * nGameFieldSize - nNumOfMines;
            this.Field = new Cell[nGameFieldSize, nGameFieldSize];
            for (int i = 0; i < nGameFieldSize; i++)
            {
                for (int j = 0; j < nGameFieldSize; j++)
                {
                    this.Field[i, j].x = i;
                    this.Field[i, j].y = j;
                    this.Field[i, j].bOpened = false;
                    this.Field[i, j].bFlag = false;
                }
            }
            
            Random rnd=new Random();
            for (int i = 0; i < nNumOfMines; i++)
            {
                int rx = rnd.Next(0, nGameFieldSize);
                int ry = rnd.Next(0, nGameFieldSize);
                while (rx == x)
                {
                    rx = rnd.Next(0, nGameFieldSize);
                }
                while (ry == y)
                {
                    ry = rnd.Next(0, nGameFieldSize);
                }
                this.Field[rx,ry].nValue = -1;
            }

            for (int i = 0; i < nGameFieldSize; i++)
            {
                for (int j = 0; j < nGameFieldSize; j++)
                {
                    if (this.Field[i, j].nValue != -1)
                    {
                        this.Field[i, j].nValue = GetNumberOfNearMines(i, j);
                    }
                }
            }

            ProcessClick(x, y);
        }

        private void MainForm_Paint(object sender, PaintEventArgs e)
        {
            Graphics g = GameField.CreateGraphics();
            SolidBrush brush = new SolidBrush(Color.SkyBlue);
            Pen pen = new Pen(Color.Purple);
            for (int i = 0; i < nGameFieldSize; i++)
            {
                for (int j = 0; j < nGameFieldSize; j++)
                {
                    g.FillRectangle(brush, i * 30, j * 30, 30, 30);
                    g.DrawRectangle(pen, i * 30, j * 30, 30, 30);
                }
            }
            brush.Dispose();
            pen.Dispose();
            g.Dispose();
        }

        private int GetNumberOfNearMines(int x, int y)
        {
            int res = 0;
            int MinX = System.Math.Max(0, x - 1);
            int MaxX = System.Math.Min(this.nGameFieldSize - 1, x + 1);
            int MinY = System.Math.Max(0, y - 1);
            int MaxY = System.Math.Min(this.nGameFieldSize - 1, y + 1);
            for (int i = MinX; i <= MaxX; i++)
            {
                for (int j = MinY; j <= MaxY; j++)
                {
                    if ((i != x || j != y) && (this.Field[i, j].nValue == -1)) res++;
                }
            }
            return res;
        }

        private void ProcessClick(int x, int y)
        {
            if (this.Field[x, y].nValue != -1 && !this.Field[x, y].bFlag)
            {
                this.Field[x, y].bOpened = true;
                if (this.Field[x, y].nValue == 0)
                {
                    OpenFreeCells(x, y);
                }
                this.nNumOfCellsToOpen--;
                if (nNumOfCellsToOpen == 0)
                {
                    this.Text = "You win!";
                }
                this.Field[x, y].Draw((Control)this.GameField);
            }
            else
            {
                if (this.Field[x, y].nValue == -1)
                {
                    ShowField();
                }
            }
        }

        private void OpenFreeCells(int x,int y)
        {
            int MinX = System.Math.Max(0, x - 1);
            int MaxX = System.Math.Min(this.nGameFieldSize - 1, x + 1);
            int MinY = System.Math.Max(0, y - 1);
            int MaxY = System.Math.Min(this.nGameFieldSize - 1, y + 1);
            for (int i = MinX; i <= MaxX; i++)
            {
                for (int j = MinY; j <= MaxY; j++)
                {
                    if (i != x || j != y)
                    {
                        if (this.Field[i, j].nValue !=-1 && !this.Field[i, j].bOpened)
                        {
                            ProcessClick(i, j);
                        }
                    }
                }
            }
        }

        private void GameField_MouseDown(object sender, MouseEventArgs e)
        {
            int CellX = (int)(e.X / 30);
            int CellY = (int)(e.Y / 30);
            if (!bGameFieldInited)
            {
                InitGameField(CellX, CellY);
                bGameFieldInited = true;
                return;
            }
            switch (e.Button)
            {
                case System.Windows.Forms.MouseButtons.Left:
                    {
                        if (!this.Field[CellX, CellY].bFlag)
                        {
                            ProcessClick(CellX, CellY);
                        }
                        break;
                    }
                case System.Windows.Forms.MouseButtons.Right:
                    {
                        if (!this.Field[CellX, CellY].bOpened)
                        {
                            this.Field[CellX, CellY].bFlag = !this.Field[CellX, CellY].bFlag;
                            this.Field[CellX, CellY].Draw((Control)this.GameField);
                        }
                        break;
                    }
                default: break;
            }
        }

        private void ShowField()
        {
            for (int i = 0; i < nGameFieldSize; i++)
            {
                for (int j = 0; j < nGameFieldSize; j++)
                {
                    this.Field[i, j].bOpened = true;
                    this.Field[i, j].Draw((Control)this.GameField);
                }
            }
            this.Text = "You lose!";
        }
    }
}
